package com.txc.cloud.admin.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.txc.cloud.admin.entity.PermissionEntity;
import com.txc.cloud.admin.mapper.PermissionMapper;
import com.txc.cloud.admin.model.dto.PermissionDto;
import com.txc.cloud.admin.model.vo.PermissionDetail;
import com.txc.cloud.admin.model.vo.PermissionModule;
import com.txc.cloud.admin.model.vo.PermissionTree;
import com.txc.cloud.admin.service.IPermissionService;
import com.txc.common.global.model.LoginUser;
import com.txc.common.global.model.SysPermission;
import com.txc.common.global.model.SysRole;
import com.txc.common.global.model.UserPermission;
import com.txc.common.utils.structure.tree.ConvertTree;
import com.txc.common.utils.structure.tree.Tree;
import com.txc.common.utils.structure.tree.TreeNode;
import com.txc.common.utils.supply.UserContext;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import jakarta.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

import static com.txc.common.global.constant.StrConstant.*;

/**
 * <p>
 * 权限表 服务实现类
 * </p>
 *
 * @author TXC
 * @since 2023-08-02
 */
@Slf4j
@Service
public class PermissionServiceImpl extends ServiceImpl<PermissionMapper, PermissionEntity> implements IPermissionService {
    @Resource
    private PermissionTree permissionTree;

    @Override
    public List<TreeNode<SysPermission>> getPermissionTree() {
        List<SysRole> roles = UserContext.getUser().getRoles();
        Set<SysPermission> permissionSet = new HashSet<>();
        roles.forEach(role -> permissionSet.addAll(role.getPermissions()));
        List<SysPermission> permissionVos = new ArrayList<>(permissionSet);
        ConvertTree<SysPermission> convertTree = new ConvertTree<>();
        Tree<SysPermission> tree = convertTree.getForest(permissionVos);
        return tree.getTreeRoot();
    }

    @Override
    public Map<String, UserPermission> getUserPermissionMap(LoginUser loginUser) {
        Set<String> permissionCodes = new HashSet<>();
        if (ObjectUtil.isNotNull(loginUser) && ObjectUtil.isNotNull(loginUser.getRoles())) {
            loginUser.getRoles().forEach(role ->
                    permissionCodes.addAll(role.getPermissions().stream().map(SysPermission::getCode).collect(Collectors.toSet()))
            );
        }
        List<PermissionEntity> permissionEntities = baseMapper.selectList(Wrappers.lambdaQuery());
        Map<String, UserPermission> userPermissions = new HashMap<>();
        permissionEntities.forEach(item -> {
            UserPermission userPermission = new UserPermission();
            userPermission.setId(item.getId());
            userPermission.setCode(item.getCode());
            userPermission.setParentCode(item.getParentCode());
            userPermission.setHasPermission(permissionCodes.contains(item.getCode()));
            userPermissions.put(item.getCode(), userPermission);
        });
        return userPermissions;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void initPermission() {
        // 从yml中获取权限树列表信息
        List<PermissionModule> permissionEntities = permissionTree.getPermission();
        // 创建一个权限容器
        List<PermissionDto> permissionContainer = new ArrayList<>();
        // 遍历权限树列表信息，将权限数据放到容器中
        for (PermissionModule item : permissionEntities) {
            ergodicPermission(item.getChild(), item.getModule(), null, permissionContainer);
        }
        flushPermission(permissionContainer);
    }

    @Override
    public List<String> getPermissionIds() {
        return baseMapper.selectList(Wrappers.lambdaQuery()).stream().map(PermissionEntity::getCode).collect(Collectors.toList());
    }

    /**
     * 创建权限
     *
     * @param permissionDtoList 权限信息列表
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void flushPermission(List<PermissionDto> permissionDtoList) {
        List<PermissionEntity> permissionEntities = new ArrayList<>();
        permissionDtoList.forEach(permission -> {
            PermissionEntity permissionEntity = new PermissionEntity();
            BeanUtils.copyProperties(permission, permissionEntity);
            permissionEntities.add(permissionEntity);
        });
        // 校验权限编码是否重复
        int effectiveSize = permissionEntities.stream().map(PermissionEntity::getCode).collect(Collectors.toSet()).size();
        if (effectiveSize != permissionEntities.size()) {
            log.error("权限重复");
            throw new RuntimeException("权限重复");
        }
        Map<String, PermissionEntity> permissionEntityMap = permissionEntities.stream().collect(Collectors.toMap(PermissionEntity::getCode, permissionEntity -> permissionEntity));
        // 删除不在权限配置中的权限
        baseMapper.delExcludeCode(permissionEntityMap.keySet());
        // 遍历权限信息，更新或新增权限信息
        permissionEntities.forEach(permissionEntity -> {
            PermissionEntity permission =
                    baseMapper.selectOne(Wrappers.<PermissionEntity>lambdaQuery().eq(PermissionEntity::getCode,
                            permissionEntity.getCode()));
            if (ObjectUtil.isNotNull(permission)) {
                baseMapper.update(permissionEntity,
                        Wrappers.<PermissionEntity>lambdaQuery().eq(PermissionEntity::getCode,
                                permissionEntity.getCode()));
                permissionEntityMap.remove(permissionEntity.getCode());
            }
        });
        // 添加新增的权限信息
        permissionEntityMap.values().forEach(permissionEntity -> baseMapper.insert(permissionEntity));
    }

    /**
     * 遍历权限
     *
     * @param permissionDetails   权限信息
     * @param module              模块名称
     * @param parentCode          父级权限编码
     * @param permissionContainer 权限信息容器
     */
    private void ergodicPermission(List<PermissionDetail> permissionDetails, String module,
                                   String parentCode, List<PermissionDto> permissionContainer) {
        if (ObjectUtil.isNotNull(permissionDetails)) {
            for (PermissionDetail permissionDetail : permissionDetails) {
                generatePermissionCode(permissionDetail, module);
                PermissionDto permissionDto = new PermissionDto();
                BeanUtils.copyProperties(permissionDetail, permissionDto);
                permissionDto.setParentCode(parentCode);
                permissionDto.setModule(module);
                permissionContainer.add(permissionDto);
                ergodicPermission(permissionDetail.getChild(), module, permissionDto.getCode(),
                        permissionContainer);
            }
        }
    }

    /**
     * 生成权限编码
     *
     * @param permissionDetail 权限信息
     * @param module           模块名
     */
    private void generatePermissionCode(PermissionDetail permissionDetail, String module) {
        if (ObjectUtil.isNull(permissionDetail.getMethodUrl()) && ObjectUtil.isNull(permissionDetail.getCode())) {
            log.error("权限{}编码和接口地址为空", permissionDetail.getName());
            throw new RuntimeException("权限编码和接口地址为空");
        }
        String code;
        if (ObjectUtil.isNotNull(permissionDetail.getMethodUrl())) {
            code = module + COLON + SLASH.concat(permissionDetail.getMethodUrl()).replace(DOUBLE_SLASH,
                    EMPTY).replace(SLASH, COLON);
        } else {
            code = permissionDetail.getCode();
        }
        permissionDetail.setCode(code);
    }
}
